#include <iostream>
#include <string>
#include <ctime>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include "LockGuard.hpp"
#include "RingQueue.hpp"
#include "Task.hpp"
#include "Log.hpp"

#define CONSUMERSIZE 10
#define PRODUCERSSIZE 10

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

template <class T>
struct ThreadData
{
    ThreadData(const std::string name, RingQueue<T> *bq)
        : _rq(bq), _name(name)
    {
    }
    RingQueue<T> *_rq;
    std::string _name;
};

void *consumers(void *args)
{
    ThreadData<Task> *td = static_cast<ThreadData<Task> *>(args);
    // RingQueue<Task> *rq = static_cast<RingQueue<Task> *>(args);
    // RingQueue *rq = static_cast<RingQueue *>(args);
    // RingQueue<int> *rq = static_cast<RingQueue<int> *>(args);
    while (true)
    {
        // sleep(1);
        // int data;
        // Task t;
        // rq->Pop(&t);
        // t();
        Task t;
        td->_rq->Pop(&t);
        t();
        LockGuard lg(&lock);
        std::cout << td->_name << " ,consumers Task : " << t.PrintResult() << std::endl;
        // std::cout << "consumers data : "<<std::endl;
    }
}

void *producer(void *args)
{
    ThreadData<Task> *td = static_cast<ThreadData<Task> *>(args);
    // RingQueue<Task> *rq = static_cast<RingQueue<Task> *>(args);
    // RingQueue<int> *rq = static_cast<RingQueue<int> *>(args);
    // RingQueue *rq = static_cast<RingQueue *>(args);
    while (true)
    {

        int data_x = rand() % 10 + 1;
        usleep(rand() % 123);
        int data_y = rand() % 10 + 1;
        int op = rand() % opres.size();
        Task t(data_x, data_y, opres[op]);
        td->_rq->Push(t);
        LockGuard lg(&lock);
        std::cout << td->_name << " , producer Task: " << t.PrintTask() << std::endl;
        // std::cout << "producer data : " << data << std::endl;?
    }
}

int main()
{

    // 单单
    // srand((uint64_t)time(nullptr) ^ pthread_self());
    // RingQueue<Task> *rq = new RingQueue<Task>(10);
    // // RingQueue<int> *rq = new RingQueue<int>(10);

    // pthread_t c, p;
    // pthread_create(&c, nullptr, consumers, (void *)rq);
    // pthread_create(&p, nullptr, producer, (void *)rq);

    // pthread_join(c, nullptr);
    // pthread_join(p, nullptr);

    // // 多多 （多线程需要加互斥锁）
    // srand((uint64_t)time(nullptr) ^ pthread_self());
    // RingQueue<Task> *rq = new RingQueue<Task>(10);
    // // RingQueue<int> *rq = new RingQueue<int>(10);

    // pthread_t c[CONSUMERSIZE], p[PRODUCERSSIZE];

    // for (int i = 0; i < CONSUMERSIZE; i++)
    // {
    //     std::string name = "consumer-";
    //     name += std::to_string(i);
    //     ThreadData<Task> *td = new ThreadData<Task>(name, rq);
    //     pthread_create(&c[i], nullptr, consumers, (void *)td);
    // }

    // for (int i = 0; i < PRODUCERSSIZE; i++)
    // {
    //     std::string name = "producers-";
    //     name += std::to_string(i);
    //     ThreadData<Task> *td = new ThreadData<Task>(name, rq);
    //     pthread_create(&p[i], nullptr, producer, (void *)td);
    // }

    // for (int i = 0; i < CONSUMERSIZE; i++)
    // {
    //     pthread_join(c[i], nullptr);
    // }

    // for (int i = 0; i < PRODUCERSSIZE; i++)
    // {
    //     pthread_join(p[i], nullptr);
    // }

    return 0;
}